using System;
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

namespace newtelligence.DasBlog.Web.Core
{
    /// <summary>
    /// Summary description for ValidTagCollection.
    /// </summary>
    [XmlRoot("validTags", Namespace="urn:newtelligence-com:dasblog:config")]
    [XmlType(Namespace="urn:newtelligence-com:dasblog:config")]
    public class ValidTagCollection : ICollection
    {
        private readonly SortedList tags = new SortedList(new CaseInsensitiveComparer(CultureInfo.InvariantCulture));
        private readonly string tagsDefinition;
        // required for xml serializer
        [XmlAnyAttribute] public XmlAttribute[] AnyAttributes;
        [XmlAnyElement] public XmlElement[] AnyElements;

        public ValidTagCollection()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ValidTagCollection"/> class.
        /// </summary>
        /// <param name="tagsDefinition">The tags definition, defined as 'tag1@att1@att2,tag2@att3@att4'.</param>
        public ValidTagCollection(string tagsDefinition)
        {
            if (tagsDefinition == null || tagsDefinition.Length == 0)
            {
                return;
            }

            this.tagsDefinition = tagsDefinition;

            string[] splitTags = tagsDefinition.Split(',');

            foreach (string tagDef in splitTags)
            {
                ValidTag tag = new ValidTag(tagDef);
                tags.Add(tag.Name, tag);
            }
        }

        /// <summary>
        /// Gets the number of allowed tags.
        /// </summary>
        /// <value>The allowed tags count.</value>
        public int AllowedTagsCount
        {
            get
            {
                int count = 0;
                foreach (ValidTag tag in this)
                {
                    if (tag.IsAllowed)
                    {
                        count ++;
                    }
                }
                return count;
            }
        }

        /// <summary>
        /// Gets the tags definition.
        /// </summary>
        /// <value>The tags definition.</value>
        [XmlIgnore]
        public string TagsDefinition
        {
            [DebuggerStepThrough]
            get { return tagsDefinition; }
        }

        /// <summary>
        /// Gets the <see cref="ValidTag"/> with the specified tag name.
        /// </summary>
        /// <value>The <see cref="ValidTag"/>.</value>
        public ValidTag this[string tagName]
        {
            get { return (ValidTag) tags[tagName]; }
        }

        public ValidTag this[int index]
        {
            get { return (ValidTag) tags.GetByIndex(index); }
            set { tags.SetByIndex(index, value); }
        }

        #region ICollection Members

        /// <summary>
        /// Copies the ValidTags to the array, starting at the index.
        /// </summary>
        /// <param name="array">The array to copy the tags to.</param>
        /// <param name="index">The index to start at.</param>
        void ICollection.CopyTo(Array array, int index)
        {
            tags.Values.CopyTo(array, index);
        }

        /// <summary>
        /// Gets the enumerator over the tags.
        /// </summary>
        /// <returns>The enumerator.</returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            // implement a ValidTagEnumerator when we actually need one
            return tags.Values.GetEnumerator();
        }

        /// <summary>
        /// Gets the number of tags in the collection.
        /// </summary>
        /// <value>The number of tags in the collection.</value>
        [XmlIgnore]
        public int Count
        {
            [DebuggerStepThrough]
            get { return tags.Count; }
        }

        /// <summary>
        /// Gets a value
        /// indicating whether access to the <see cref="T:System.Collections.ICollection"/> is synchronized
        /// (thread-safe).
        /// </summary>
        /// <value>Always returns <see langword="false" />.</value>
        [XmlIgnore]
        bool ICollection.IsSynchronized
        {
            [DebuggerStepThrough]
            get { return false; }
        }

        /// <summary>
        /// Gets an object that
        /// can be used to synchronize access to the <see cref="T:System.Collections.ICollection"/>.
        /// </summary>
        /// <value>An object to synchronize access to the collection.</value>
        [XmlIgnore]
        object ICollection.SyncRoot
        {
            [DebuggerStepThrough]
            get { return tags.SyncRoot; }
        }

        #endregion

        public void Add(ValidTag tag)
        {
            if (tag == null)
            {
                throw new ArgumentNullException("tag");
            }

            tags.Add(tag.Name, tag);
        }

        /// <summary>
        /// Determines if the tagName is valid.
        /// </summary>
        /// <param name="tagName">The tag to validate.</param>
        /// <returns><see langword="true" /> if the tagName is valid; otherwise, <see langword="false" />.</returns>
        public bool IsValidTag(string tagName)
        {
            return tags[tagName] != null && ((ValidTag) tags[tagName]).IsAllowed;
        }

        /// <summary>
        /// Returns a <see cref="T:System.String"/> that represents the current <see cref="ValidTag"/>.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"/> that represents the current <see cref="ValidTag"/>.
        /// </returns>
        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();

            foreach (ValidTag tag in this)
            {
                if (tag.IsAllowed)
                {
                    sb.Append(tag.ToString() + ", ");
                }
            }

            if (sb.Length > 0)
            {
                // remove trailing ", "
                sb.Remove(sb.Length - 2, 2);
            }

            return sb.ToString();
        }

        public string ToJavaScriptArray()
        {
            StringBuilder sb = new StringBuilder();

            foreach (ValidTag tag in this)
            {
                if (tag.IsAllowed)
                {
                    sb.Append("'" + tag.Name + "', ");
                }
            }

            if (sb.Length > 0)
            {
                // remove trailing ", "
                sb.Remove(sb.Length - 2, 2);
            }

            return sb.ToString();
        }
    }
}